#include <Ice/Application.h>
#include <FileTransfer.h>

using namespace std;
using namespace Ice;
using namespace FileTransfer;

class FileI
  : public File
{
public:
  
  FileI(FILE* fp, int num) :
    _fp(fp),
    _num(num),
    _bytes(new Ice::Byte[num])
  {
  }

  ~FileI()
  {
    delete[] _bytes;
  }
  
  virtual void next_async(const ::FileTransfer::AMD_File_nextPtr&, const ::Ice::Current&);

private:

  FILE* _fp;
  const int _num;
  Ice::Byte* _bytes;
  
};

void
FileI::next_async(const ::FileTransfer::AMD_File_nextPtr& cb,
		  const ::Ice::Current& current)
{
  pair <const Ice::Byte*, const Ice::Byte*> ret(0, 0);
  ssize_t r = fread(_bytes, 1, _num, _fp);
  if (r == 0) {
    fclose(_fp);
    current.adapter->remove(current.id);
  }
  else {
    ret.first = _bytes;
    ret.second = _bytes + r;
  }
  cb->ice_response(ret);
}

class FileStoreI
  : public FileStore
{
public:
  FileStoreI();
  ~FileStoreI();
  virtual ::FileTransfer::FilePrx read(const ::std::string&, ::Ice::Int, const ::Ice::Current&);
  void write(const ::std::string&, ::Ice::Int, const ::Ice::ByteSeq&, const ::Ice::Current&);
private:
  ::Ice::ByteSeq _bytes;
};

FileStoreI::FileStoreI()
{
}

FileStoreI::~FileStoreI()
{
}

::FileTransfer::FilePrx
FileStoreI::read(const ::std::string& name,
		 ::Ice::Int num,
		 const ::Ice::Current& current)
{
  
  FILE* fp = fopen(name.c_str(), "rb");

  if (fp == 0) {
    FileAccessException ex;
    ex.reason = "cannot open '" + name + "' for reading: " + strerror(errno);
    throw ex;
  }

  return FilePrx::uncheckedCast(current.adapter->addWithUUID(new FileI(fp, num)));

}

void
FileStoreI::write(const ::std::string& name,
		  ::Ice::Int offset,
		  const ::Ice::ByteSeq& bytes,
		  const ::Ice::Current&)
{
}

class Server
  : virtual public Ice::Application
{
public:
  virtual int run (int argc,
		   char *argv[])
  {
    Ice::ObjectAdapterPtr adapter = communicator()->
      createObjectAdapterWithEndpoints("FileTransferAdapter", "tcp -h 161.67.38.113 -p 10000");
    Ice::ObjectPtr object = new FileStoreI;
    adapter->add(object, communicator()->stringToIdentity("FileStore"));
    adapter->activate();

    communicator()->waitForShutdown();
    return EXIT_SUCCESS;
  }
};

int main(int argc,
	 char* argv[])
{
  Server server;
  return server.main(argc, argv, "server.cfg");
}
